package com.leo;

import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.app.GameSettings;
import com.almasb.fxgl.core.math.FXGLMath;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.dsl.components.ExpireCleanComponent;
import com.almasb.fxgl.dsl.components.OffscreenCleanComponent;
import com.almasb.fxgl.dsl.components.ProjectileComponent;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.input.UserAction;
import com.almasb.fxgl.physics.BoundingShape;
import com.almasb.fxgl.physics.CollisionHandler;
import com.almasb.fxgl.time.LocalTimer;
import javafx.animation.FadeTransition;
import javafx.animation.ParallelTransition;
import javafx.animation.ScaleTransition;
import javafx.geometry.Point2D;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.util.Duration;

import java.util.ArrayList;
import java.util.Map;

/**
 * @Author: wangss
 * @CreateTime: 2023-05-24  21:34
 * @Description: 坦克大战
 */
public class TankApp extends GameApplication {

    private Entity tankEntity;

    private boolean isMoving;

    private Dir dir;
    private Entity bullet;

    enum Dir {
        UP, DOWN, LEFT, RIGHT
    }

    private Point2D left = new Point2D(-1, 0);
    private Point2D right = new Point2D(1, 0);
    private Point2D up = new Point2D(0, -1);
    private Point2D down = new Point2D(0, 1);

    private Point2D direction;

    // 使用射击的定时器处理子弹
    private LocalTimer shootTimer;

    /**
     * 初始化设置
     *
     * @param gameSettings
     */
    @Override
    protected void initSettings(GameSettings gameSettings) {
        gameSettings.setWidth(800);
        gameSettings.setHeight(600);
        gameSettings.setTitle("Tank Game");
        gameSettings.setVersion("1.1");
        // 设置图标
        gameSettings.setAppIcon("ui/icon.png");
    }

    @Override
    protected void initGameVars(Map<String, Object> vars) {
        // int
        vars.put("score", 0);
        // dubbo
        vars.put("x", 0d);
        // object
        vars.put("b", new ArrayList<>());
        // String
        vars.put("s", "123");
    }

    /**
     * 初始化游戏
     */
    @Override
    protected void initGame() {

        FXGL.getip("score").addListener((observable, oldValue, newValue) -> {
            if (newValue.intValue() >= 50) {
                FXGL.getNotificationService().pushNotification("你好棒哦");
                FXGL.play("item.wav");
            }
        });

        shootTimer = FXGL.newLocalTimer();
        Canvas canvas = new Canvas(100, 100);
        GraphicsContext context2D = canvas.getGraphicsContext2D();
        // 填充颜色
        context2D.setFill(Color.web("#ffec03"));
        context2D.fillRect(0, 0, 80, 30);

        context2D.setFill(Color.web("#cebc17"));
        context2D.fillRect(15, 30, 50, 40);

        context2D.setFill(Color.web("#ffec03"));
        context2D.fillRect(0, 70, 80, 30);

        context2D.setFill(Color.web("#f9ee8a"));
        context2D.fillRect(40, 40, 60, 20);

        // 游戏里的对象entity 类似于 Java中的object
        tankEntity = FXGL.entityBuilder()
                // view 决定游戏实体的外观
                .view(canvas)
                // bbox决定游戏实体的真实大小
                .bbox(BoundingShape.box(100, 100))
                // 可以有多个视图
                .view(new Text("坦克1"))
                .build();
        // 设置中心点
        tankEntity.setRotationOrigin(new Point2D(50, 50));

        // 获取实体的中心
        Point2D center = tankEntity.getCenter();
        System.out.println(center.getX() + "-----" + center.getY());

        // 获取游戏世界添加对象
        FXGL.getGameWorld().addEntities(tankEntity);
        dir = Dir.RIGHT;

        // 创建敌人
        createEnemy();
    }

    private void createEnemy() {
        FXGL.entityBuilder()
                .type(GameType.ENEMY)
                .at(FXGLMath.random(60, 800 - 60), FXGLMath.random(60, 600 - 60))
                .viewWithBBox(new Rectangle(60, 60, Color.BLUE))
                // 碰撞
                .collidable()
                .buildAndAttach();
    }

    /**
     * 获取输入
     */
    @Override
    protected void initInput() {
        FXGL.getInput().addAction(new UserAction("Move Up") {
            @Override
            protected void onAction() {
                if (isMoving) {
                    return;
                }
                dir = Dir.UP;
                isMoving = true;
                tankEntity.translateY(-3);
                tankEntity.setRotation(270);
            }
        }, KeyCode.UP);

        FXGL.getInput().addAction(new UserAction("Move Down") {
            @Override
            protected void onAction() {
                if (isMoving) {
                    return;
                }
                dir = Dir.DOWN;
                isMoving = true;
                tankEntity.translateY(3);
                tankEntity.setRotation(90);
            }
        }, KeyCode.DOWN);

        FXGL.getInput().addAction(new UserAction("Move Left") {
            @Override
            protected void onAction() {
                if (isMoving) {
                    return;
                }
                dir = Dir.LEFT;
                isMoving = true;
                tankEntity.translateX(-3);
                tankEntity.setRotation(180);
            }
        }, KeyCode.LEFT);

        FXGL.getInput().addAction(new UserAction("Move Right") {
            @Override
            protected void onAction() {
                if (isMoving) {
                    return;
                }
                dir = Dir.RIGHT;
                isMoving = true;
                tankEntity.translateX(3);
                tankEntity.setRotation(0);
            }
        }, KeyCode.RIGHT);

        FXGL.getInput().addAction(new UserAction("Shoot") {
            @Override
            protected void onAction() {
                // 发射时间间隔小于0.25s，则不在进行发射
                if (!shootTimer.elapsed(Duration.seconds(0.25))) {
                    return;
                }
                // 定时器归零
                shootTimer.capture();

                // 射击音效
                FXGL.play("normalFire.wav");

                // 子弹方向
                switch (dir) {
                    case UP -> direction = up;
                    case DOWN -> direction = down;
                    case LEFT -> direction = left;
                    case RIGHT -> direction = right;
                    default -> direction = left;
                }
                // 子弹实体，创建并添加
                bullet = FXGL.entityBuilder()
                        .type(GameType.BULLET)
                        .at(tankEntity.getCenter().getX() - 10, tankEntity.getCenter().getY() - 10)
                        .viewWithBBox(new Rectangle(20, 20))
                        // 子弹组件
                        .with(new ProjectileComponent(direction, 600))
                        // 屏幕外移除组件，超出屏幕会移除子弹实体
                        .with(new OffscreenCleanComponent())
                        // 碰撞
                        .collidable()
                        .buildAndAttach();

            }
        }, KeyCode.SPACE);
    }

    @Override
    protected void onUpdate(double tpf) {
        isMoving = false;
        // 打印实体的数量
//        System.out.println(FXGL.getGameWorld().getEntities().size());
    }

    @Override
    protected void initPhysics() {

        // 物理世界碰撞检测
        FXGL.getPhysicsWorld().addCollisionHandler(new CollisionHandler(GameType.BULLET, GameType.ENEMY) {

            @Override
            protected void onCollisionBegin(Entity bullet, Entity enemy) {

                // 每次增加10分
                FXGL.inc("score", 10);

                // 发生碰撞，从游戏世界移除
                bullet.removeFromWorld();

                // 爆炸音效
                FXGL.play("normalBomb.wav");

                // 增加爆炸效果
                Point2D center = enemy.getCenter();

                enemy.removeFromWorld();

                Duration seconds = Duration.seconds(.5);
                Circle circle = new Circle(10, Color.RED);
                // 创建一个爆炸实体
                Entity boom = FXGL.entityBuilder()
                        .at(center)
                        .view(circle)
                        // 超过指定时间移除实体
                        .with(new ExpireCleanComponent(seconds))
                        .buildAndAttach();
                ScaleTransition st = new ScaleTransition(seconds, circle);
                st.setToX(10);
                st.setToY(10);

                FadeTransition ft = new FadeTransition(seconds, circle);
                ft.setToValue(0);

                ParallelTransition pt = new ParallelTransition(st, ft);
//                pt.setOnFinished(actionEvent -> boom.removeFromWorld());
                pt.play();

                createEnemy();
            }

            @Override
            protected void onCollision(Entity a, Entity b) {
                super.onCollision(a, b);
            }
        });
    }

    @Override
    protected void initUI() {
//        Text text = FXGL.addVarText("score", 20, 20);
//        text.setFill(Color.BLUE);
        // 设置字体大小需要先解除绑定
//        text.fontProperty().unbind();
//        text.setFont(Font.font(20));

        // 另一种添加节点的方法
        Text text1 = FXGL.getUIFactoryService().newText(FXGL.getip("score").asString("SCORE: %d"));
        text1.setLayoutX(20);
        text1.setLayoutY(20);
        text1.setFill(Color.BLUE);
        FXGL.addUINode(text1);
    }

    @Override
    protected void onPreInit() {
        // 预先加载资源
        // 设置游戏的初始化音量
        // 背景音效
        FXGL.getSettings().setGlobalMusicVolume(0.5);

//        FXGL.loopBGM("bg.mp3");
    }

    public static void main(String[] args) {
        launch(args);
    }
}
